
#include "bpt_acsvr.h"
#include "duplicate_login_handler.h"
#include "gsmeg_link_manager.h"
Z_API bpt_acsvr_ctx_t *g_ctx;

#define GTP_VER_TAG    "X01"
#define GTP_LEN_TAG    "X02"
#define MSG_TYPE_TAG   "X03"
#define SEQ_SERI_TAG   "X04"
#define SEQ_NO_TAG     "X05"
#define CHAIN_FLAG_TAG "X06"
#define ROOT_ID_TAG    "X07"

#define RSP_CODE_TAG    "X39"
#define RSP_MSG_TAG     "X40"

#define MSG_TYPE_RESPONSE   1
#define MSG_TYPE_BROADCAST  2

static void __add_gtp_head(z_hash_t *gtp_hash,char *msg_type,char *root_id){
    zH_strinsert_str(gtp_hash,GTP_VER_TAG,"GTP1.0");
    zH_strinsert_str(gtp_hash,GTP_LEN_TAG,"0"); 
    if(msg_type) zH_strinsert_str(gtp_hash,MSG_TYPE_TAG,msg_type);
    zH_strinsert_str(gtp_hash,SEQ_SERI_TAG,"0"); 
    zH_strinsert_str(gtp_hash,SEQ_NO_TAG,"0"); 
    zH_strinsert_str(gtp_hash,CHAIN_FLAG_TAG,"L");
    if(root_id) zH_strinsert_str(gtp_hash,ROOT_ID_TAG,root_id);
}

int convert_handler_gsmeg2gtp(z_hash_t *gsmeg_hash,long long cmd,int con_len, z_acsvr_head_t *ac_head, z_gtp_t *gtp,bpt_convert_handle_t *bpt_cvt_handler,int gsmeg_msg_type){
    char *gtp_msg = (char *)(gtp+1);
    int rsp_code = 0, ret = 0;
    z_hash_t *gtp_hash =zH_init();

    //get msg_type  
    z_string_t *msg_type = zH_llfind_string(bpt_cvt_handler->gsmeg2gtp_cmd_map_,cmd);
    _CHECK_VAL_TRUE_LOG_GOTO_ERR( NULL == msg_type,"msg type not found for cmd[%d]",cmd)
        	 
    //add gtphead into gtphash and gsmeg hash to hash
    if(gsmeg_msg_type == MSG_TYPE_RESPONSE){
        z_string_t *hash_rsp_code = zH_strfind_string(gsmeg_hash,GSMEG_RSP_CODE_TAG);
        _CHECK_VAL_TRUE_RET(NULL == hash_rsp_code, 0, "rsp code missed in gsmeg");
        if(0 == strcmp( string2str(hash_rsp_code),GSMEG_SUCCESS_RSP_CODE)){
            ret = gsmeg2gtp_hash2hash(cmd,gsmeg_hash,gtp_hash,bpt_cvt_handler->gsmeg2gtp_field_map_,&rsp_code,TRUE);
	        _CHECK_VAL_TRUE_LOG_GOTO_ERR( ret!= 0,"gsmeg hash to gtp hash failure[%d]",rsp_code)	
        }else{
            ret = gsmeg2gtp_hash2hash(cmd,gsmeg_hash,gtp_hash,bpt_cvt_handler->gsmeg2gtp_field_map_,&rsp_code,FALSE);
	        _CHECK_VAL_TRUE_LOG_GOTO_ERR( ret!= 0,"gsmeg hash to gtp hash failure[%d]",rsp_code)	
        }
    	__add_gtp_head(gtp_hash,string2str(msg_type),ac_head->root_id_);
	}else{
        ret = gsmeg2gtp_hash2hash(cmd,gsmeg_hash,gtp_hash,bpt_cvt_handler->gsmeg2gtp_field_map_,&rsp_code,TRUE);
	    _CHECK_VAL_TRUE_LOG_GOTO_ERR( ret!= 0,"gsmeg hash to gtp hash failure[%d]",rsp_code)	
		__add_gtp_head(gtp_hash,string2str(msg_type),NULL);
	}
    //hash2gtp
    int offset= 0, available_len = gtp->con_len_;
    ret = z_hash2gtp(gtp_hash,gtp_msg,&offset,&available_len,bpt_cvt_handler->gtp_escape_parser_);
	_CHECK_VAL_TRUE_LOG_GOTO_ERR( ret!= 0,"gsmeg cvt to gtp convert failure")	
	
	//set gtp head
	set_gtp_head(gtp,GTP_TYPE_STRING,offset);
	if(gtp_hash) zH_free(gtp_hash);
	
    return 0;   

ERROR:
	if(gtp_hash) zH_free(gtp_hash);
	return -1;     
}

static int __filter_rsp_msg(int dev_id, int this_dev_id){
    if(dev_id == this_dev_id){
        return FALSE;
    }else{
        return TRUE;
    }
}

static z_hash_t *__get_gsmeghash_from_gsmeg(z_gsmeg_t *gsmeg_msg){
	char *json_msg = (char *)(gsmeg_msg+1);    
    z_buffer_t json_bf = {
             .used_ = gsmeg_msg->size_-sizeof(z_gsmeg_t),
             .size_ = gsmeg_msg->size_-sizeof(z_gsmeg_t),
             .ptr_  = json_msg,
    };
    Z_LOG_DEBUG("json buff %b",&json_bf);
    z_hash_t *gsmeg_hash  =z_json2hash(&json_bf);
	return gsmeg_hash;
}	

static int __get_ac_head_from_gsmeg(z_hash_t*gsmeg_hash,z_acsvr_head_t *ac_head){	
  	z_string_t *tmp = zH_strfind_string(gsmeg_hash,GSMEG_ACSVR_HEAD_TAG);
    _CHECK_VAL_TRUE_RET(tmp == NULL,-1,"acsvr head not found in gsmeg hash");

    char ac_head_buff[AC_HEAD_BUFF_LENGTH+3] = {0};
    if( (size_t)(-1)== z_base64_decode(string2str(tmp), ac_head_buff, AC_HEAD_BUFF_LENGTH+3)){
        Z_LOG_ERROR("base64 decode acsvr head error");
        return -1;
    }

    memcpy(ac_head,ac_head_buff,sizeof(z_acsvr_head_t));
	return 0;
}

static int __conver_bptsvr_rspcode(z_hash_t *gsmeg_hash,z_hash_t *errcode_map){
	long long rsp_code=0;
	_CHECK_VAL_TRUE_RET(NULL == zH_strfind_ll(gsmeg_hash,GSMEG_RSP_CODE_TAG,&rsp_code),-1,"rsp_code field not found in gsmeg hash");
    char convert_rsp_code[RSPCODE_LENGTH]={0};
    if(0 == rsp_code){
        snprintf(convert_rsp_code,RSPCODE_LENGTH, "RSP%06lld",rsp_code);	
    }else{
        snprintf(convert_rsp_code,RSPCODE_LENGTH, "RSP0%d%04lld",BPTSVR_ERRCODE_HEAD,rsp_code);	
    }
    zH_delete_by_str(gsmeg_hash,GSMEG_RSP_CODE_TAG);
    zH_strinsert_str(gsmeg_hash,GSMEG_RSP_CODE_TAG,convert_rsp_code);
    return 0;   		
}

int conver_handler_rspcode(z_hash_t *gsmeg_hash,z_hash_t *errcode_map){
	long long rsp_code=0;
    int distory_flag =0;
	_CHECK_VAL_TRUE_RET(NULL == zH_strfind_ll(gsmeg_hash,GSMEG_RSP_CODE_TAG,&rsp_code),-1,"rsp_code field not found in gsmeg hash");

	z_hash_t *rsp_hash = (z_hash_t *)zH_llfind(errcode_map,rsp_code);
    if(NULL == rsp_hash){
    	Z_LOG_ERROR("config not found for rspcode[%d]in errcode map",rsp_code);
        rsp_hash = zH_init();
        distory_flag =1;
        zH_strinsert_ll(rsp_hash,ERR_CFG_RSP_CODE,-1);
        zH_strinsert_str(rsp_hash,ERR_CFG_RSP_MSG,"errcode not config");
    }
	long long gtp_rsp_code =0;
	_CHECK_VAL_TRUE_RET(NULL == zH_strfind_ll(rsp_hash,ERR_CFG_RSP_CODE,&gtp_rsp_code),-1,"gtp rsp_code not found for rspcode in errcode map");
    char convert_rsp_code[RSPCODE_LENGTH]={0};
    snprintf(convert_rsp_code,RSPCODE_LENGTH, "RSP%06lld",gtp_rsp_code);	
    zH_delete_by_str(gsmeg_hash,GSMEG_RSP_CODE_TAG);
    zH_strinsert_str(gsmeg_hash,GSMEG_RSP_CODE_TAG,convert_rsp_code);

	z_string_t *gtp_rsp_msg = zH_strfind_string(rsp_hash,ERR_CFG_RSP_MSG);
    if(NULL == gtp_rsp_msg){
		Z_LOG_ERROR("gtp rsp_msg not found for rspcode in errcode map");
	}else{
    	zH_delete_by_str(gsmeg_hash,GSMEG_RSP_MSG_TAG);
	    zH_strinsert_str(gsmeg_hash,GSMEG_RSP_MSG_TAG,string2str(gtp_rsp_msg));
	}
    if(TRUE == distory_flag) zH_free(rsp_hash);
    return 0;   		
}


static int __trader_login_rsp_success_handler(z_hash_t *gsmeg_hash,long long channel_id,int filter_value){
    z_string_t *trader_id = zH_strfind_string(gsmeg_hash,GSMEG_TRADER_ID_TAG);
	_CHECK_VAL_TRUE_RET(NULL == trader_id, 0, "traderID missed in gsmeg");
   
    z_string_t *seat_id = zH_strfind_string(gsmeg_hash,GSMEG_SEAT_ID_TAG);
	_CHECK_VAL_TRUE_RET(NULL == seat_id, 0, "seatID missed in gsmeg");

    long long exist_channel_id =0;
    if(FALSE == filter_value){//same dev_id
        z_link_t *link_info = find_link(g_ctx->link_id_map_,channel_id);
        _CHECK_VAL_TRUE_RET(NULL == link_info, 0, "link[%d] has already disconnected",channel_id);
        if(NULL == zH_strfind_ll(g_ctx->trader_id_map_,string2str(trader_id),&exist_channel_id)){
            WARNING_PRINT("same devid: trader [%s] is not found",string2str(trader_id));
        }
        if(channel_id == exist_channel_id){
            //the first login_req
            DEBUG_PRINT("the first trader login_req in the same dev_id");
            link_update_state(link_info,LOGIN);
            set_seat_flow_ctrl(g_ctx->flow_ctrl_,link_info->seat_id_,channel_id);
            trader_monitor_log(AC_TRADER_LOGIN, g_ctx->dev_id_,link_info->seat_id_, link_info->trader_id_);
        }else{
            //the second login_req: logout exist_channel_id and update
            DEBUG_PRINT("the second trader login_req in the same dev_id");
            link_update_state(link_info,LOGIN);
            set_seat_flow_ctrl(g_ctx->flow_ctrl_,link_info->seat_id_,channel_id);
            z_link_t *exist_link_info = find_link(g_ctx->link_id_map_,exist_channel_id);
            if(NULL == exist_link_info){
                WARNING_PRINT("link[%d] has already disconnected",exist_channel_id);
                insert_trader_map_info(g_ctx->seat_id_map_,g_ctx->trader_id_map_,string2str(seat_id), string2str(trader_id),link_info->link_id_);
            }else{
                send_trader_duplicate_login_notify(exist_link_info,g_ctx->gtp_pub_);//noted:send M992 before disconnect when duplicate login
                del_link(g_ctx->link_id_map_,exist_link_info);
                ac_disconnect(exist_channel_id);    
                trader_monitor_log(AC_TRADER_LOGOUT, g_ctx->dev_id_,exist_link_info->seat_id_, exist_link_info->trader_id_);
                update_trader_map_info(g_ctx->seat_id_map_,g_ctx->trader_id_map_,exist_link_info->seat_id_,exist_link_info->trader_id_,string2str(seat_id), string2str(trader_id),exist_channel_id, link_info->link_id_);
            }
            trader_monitor_log(AC_TRADER_LOGIN, g_ctx->dev_id_,string2str(seat_id), string2str(trader_id));
        }
    }else{//different dev_id
        DEBUG_PRINT("different dev_id recv the trader login_req");
        _CHECK_VAL_TRUE_RET_LOG_DEBUG(NULL == zH_strfind_ll(g_ctx->trader_id_map_,string2str(trader_id),&exist_channel_id),0,"different devid: trader [%s] is not found",string2str(trader_id));
        z_link_t *exist_link_info = find_link(g_ctx->link_id_map_,exist_channel_id);
        _CHECK_VAL_TRUE_RET(NULL == exist_link_info, 0, "link[%d] has already disconnected",exist_channel_id);
        send_trader_duplicate_login_notify(exist_link_info,g_ctx->gtp_pub_);//noted:send M992 before disconnect when duplicate login
        clean_trader_map_info(g_ctx->seat_id_map_,g_ctx->trader_id_map_,exist_link_info->seat_id_,exist_link_info->trader_id_,exist_channel_id);
        del_link(g_ctx->link_id_map_,exist_link_info);
        ac_disconnect(exist_channel_id);
        trader_monitor_log(AC_TRADER_LOGOUT,g_ctx->dev_id_,exist_link_info->seat_id_,exist_link_info->trader_id_);
    }
    return 0;
}

static int __trader_login_rsp_failed_handler(z_hash_t *gsmeg_hash,long long channel_id,int filter_value){
    long long exist_channel_id =0;
    if(FALSE == filter_value){//same dev_id
        z_link_t *link_info = find_link(g_ctx->link_id_map_,channel_id);
        _CHECK_VAL_TRUE_RET(NULL == link_info, 0, "link[%d] has already disconnected",channel_id);
        if(NULL == zH_strfind_ll(g_ctx->trader_id_map_,link_info->trader_id_,&exist_channel_id)){
            WARNING_PRINT("same dev_id: trader [%s] is not found",link_info->trader_id_);
        }
        if(channel_id == exist_channel_id){
            //the first login_req
            DEBUG_PRINT("the first trader login_req failed with the same dev_id");
            clean_trader_map_info(g_ctx->seat_id_map_,g_ctx->trader_id_map_,link_info->seat_id_,link_info->trader_id_ ,link_info->link_id_);
            del_link(g_ctx->link_id_map_,link_info);
            ac_disconnect(channel_id);    	
            trader_monitor_log(AC_TRADER_LOGOUT,g_ctx->dev_id_,link_info->seat_id_, link_info->trader_id_);
        }else{
            del_link(g_ctx->link_id_map_,link_info);
            ac_disconnect(channel_id);    	
            trader_monitor_log(AC_TRADER_LOGOUT,g_ctx->dev_id_,link_info->seat_id_, link_info->trader_id_);

        }
    }
    return 0;
}

static int  __trader_login_rsp_handler(z_hash_t *gsmeg_hash,long long channel_id,int filter_value){
    int ret = 0;
     z_string_t *rsp_code = zH_strfind_string(gsmeg_hash,GSMEG_RSP_CODE_TAG);
	_CHECK_VAL_TRUE_RET(NULL == rsp_code, 0, "rsp code missed in gsmeg");
    if(0 == strcmp( string2str(rsp_code),GSMEG_SUCCESS_RSP_CODE)){
        ret = __trader_login_rsp_success_handler(gsmeg_hash,channel_id,filter_value);
    }else{
        ret = __trader_login_rsp_failed_handler(gsmeg_hash,channel_id,filter_value);
    }
    return ret; 
    
}
static int __user_login_rsp_success_handler(z_hash_t *gsmeg_hash,long long channel_id,int filter_value){
    z_string_t *user_id = zH_strfind_string(gsmeg_hash,GSMEG_USER_ID_TAG);
	_CHECK_VAL_TRUE_RET(NULL == user_id, 0, "userID missed in gsmeg");

    long long exist_channel_id = 0;
    if(FALSE == filter_value){//same dev_id
        z_link_t *link_info = find_link(g_ctx->link_id_map_,channel_id);
        _CHECK_VAL_TRUE_RET(NULL == link_info, 0, "link[%d] has already disconnected",channel_id);
        if(NULL == zH_strfind_ll(g_ctx->user_id_map_,string2str(user_id),&exist_channel_id)){
            WARNING_PRINT("same dev_id: user [%s] is not found",string2str(user_id));
        }
        if(channel_id == exist_channel_id){
            DEBUG_PRINT("the first user login_req in the same dev_id");
            link_update_state(link_info,LOGIN);
        }else{
            DEBUG_PRINT("the second user login_req in the same dev_id");
            z_link_t *exist_link_info = find_link(g_ctx->link_id_map_,exist_channel_id);
            if(NULL == exist_link_info){
                WARNING_PRINT("link[%d] has already disconnected",exist_channel_id);
                insert_user_map_info(g_ctx->user_id_map_,string2str(user_id), channel_id);
            }else{
                send_user_duplicate_login_notify(exist_link_info,g_ctx->gtp_pub_);//noted:send M992 before disconnect when duplicate login
                del_link(g_ctx->link_id_map_,exist_link_info);
                ac_disconnect(exist_channel_id);    	
                update_user_map_info(g_ctx->user_id_map_,exist_link_info->trader_id_,string2str(user_id), channel_id);
            }
            link_update_state(link_info,LOGIN);
        }
    }else{//different dev_id
        DEBUG_PRINT("different dev_id recv the user login_req");
        _CHECK_VAL_TRUE_RET_LOG_DEBUG(NULL == zH_strfind_ll(g_ctx->user_id_map_,string2str(user_id),&exist_channel_id),0,"different dev_id: user [%s] is not found",string2str(user_id));
        z_link_t *exist_link_info = find_link(g_ctx->link_id_map_,exist_channel_id);
        _CHECK_VAL_TRUE_RET(NULL == exist_link_info, 0, "link[%d] has already disconnected",exist_channel_id);
        send_user_duplicate_login_notify(exist_link_info,g_ctx->gtp_pub_);//noted:send M992 before disconnect when duplicate login
        clean_user_map_info(g_ctx->user_id_map_,exist_link_info->trader_id_);
        del_link(g_ctx->link_id_map_,exist_link_info);
        ac_disconnect(exist_channel_id);

    }
    return 0;
}


static int __user_login_rsp_failed_handler(z_hash_t *gsmeg_hash,long long channel_id,int filter_value){
    long long exist_channel_id = 0;
    if(FALSE == filter_value){//same dev_id
        z_link_t *link_info = find_link(g_ctx->link_id_map_,channel_id);
        _CHECK_VAL_TRUE_RET(NULL == link_info, 0, "link[%d] has already disconnected",channel_id);
        if(NULL == zH_strfind_ll(g_ctx->user_id_map_,link_info->trader_id_,&exist_channel_id)){
            WARNING_PRINT("same devid: user [%s] is not found",link_info->trader_id_);
        }
        if(channel_id == exist_channel_id){
            //the first login_req
            DEBUG_PRINT("the first user login_req failed in the same dev_id");
            clean_user_map_info(g_ctx->user_id_map_,link_info->trader_id_);
            del_link(g_ctx->link_id_map_,link_info);
            ac_disconnect(channel_id);    	
        }else{
            del_link(g_ctx->link_id_map_,link_info);
            ac_disconnect(channel_id);    	
        }
    }
    return 0;
}


static int __user_login_rsp_handler(z_hash_t *gsmeg_hash,long long channel_id,int filter_value){
    int ret = 0 ;
    z_string_t *rsp_code =zH_strfind_string(gsmeg_hash,GSMEG_RSP_CODE_TAG);
	_CHECK_VAL_TRUE_RET(NULL == rsp_code, 0, "rsp code missed in gsmeg");
    if(0 == strcmp( string2str(rsp_code),GSMEG_SUCCESS_RSP_CODE)){
        ret = __user_login_rsp_success_handler(gsmeg_hash,channel_id,filter_value);
    }else{
        ret = __user_login_rsp_failed_handler(gsmeg_hash,channel_id,filter_value);
    }
    return ret;
}

static void __delete_and_disconnect(char *seat_id,char * trader_id){
     z_hash_t *seat_link = (z_hash_t *)zH_strfind(g_ctx->seat_id_map_,seat_id);
     if(NULL != seat_link ){
        long long channel_id = 0;
        if ( NULL != zH_strfind_ll(g_ctx->trader_id_map_,trader_id,&channel_id)){
              delete_from_map_by_id(g_ctx->trader_id_map_,trader_id);
              zH_delete_by_ll(seat_link,channel_id);
              disconnect(g_ctx->link_id_map_,channel_id);
              trader_monitor_log(AC_TRADER_LOGOUT, g_ctx->dev_id_,seat_id, trader_id);
        }else{
            WARNING_PRINT("tarder_id[%s] has already delete",trader_id);
        }
     }else{
        WARNING_PRINT("seat_id[%s] has already delete",seat_id);
     }
}


static int __trader_force_logout(z_hash_t *gtp_hash){
	 z_string_t *trader_id =zH_strfind_string(gtp_hash,GSMEG_TRADER_ID_TAG);
	_CHECK_VAL_TRUE_RET(NULL == trader_id, -1, "trader id missed in gsmeg");
	 z_string_t *seat_id =zH_strfind_string(gtp_hash,GSMEG_SEAT_ID_TAG);
	_CHECK_VAL_TRUE_RET(NULL == seat_id, -1, "seat id missed in gsmeg");	
	__delete_and_disconnect(string2str(seat_id),string2str(trader_id));		 
	return 0;
}	

static int __rsp_gsmeg_msg_handler(z_hash_t *gsmeg_hash ,long long cmd,size_t gsmeg_len){    
    z_acsvr_head_t ac_head;
    memset(&ac_head,0,sizeof(z_acsvr_head_t));
    _CHECK_VAL_TRUE_RET(0 != __get_ac_head_from_gsmeg(gsmeg_hash,&ac_head),-1,"get acsvr head failure");

    int ret = __conver_bptsvr_rspcode(gsmeg_hash,g_ctx->cvt_handle_->errcode_map_);
    _CHECK_VAL_TRUE_RET(ret != 0,-1,"convert errcode failure");
    

    if( FALSE == __filter_rsp_msg(ac_head.dev_id_,g_ctx->dev_id_)){
        g_ctx->gtp_pub_->con_len_ = GTP_CONT_LEN;
    	ret =convert_handler_gsmeg2gtp(gsmeg_hash,cmd, gsmeg_len,&ac_head, g_ctx->gtp_pub_,g_ctx->cvt_handle_,MSG_TYPE_RESPONSE);	
        _CHECK_VAL_TRUE_RET(ret != 0,-1,"response msg to channel convert failure");
        
        z_link_t  *link_info = find_link(g_ctx->link_id_map_,ac_head.channel_id_);
        _CHECK_VAL_TRUE_RET_INFO_PRINT(NULL == link_info, 0, "link[%d] has already disconnected",ac_head.channel_id_);
        send_gtp_by_link_info(g_ctx->safe_server_link_,g_ctx->gtp_pub_,link_info);
        
        PRINT_GTP(g_ctx->gtp_pub_);
        if( cmd == cmd_bpt_rsp_trader_login){
            ret = __trader_login_rsp_handler(gsmeg_hash,ac_head.channel_id_,FALSE);
        }
        if(cmd == cmd_bpt_rsp_monitor_login){
            ret = __user_login_rsp_handler(gsmeg_hash,ac_head.channel_id_,FALSE);
        }
    }else{
        DEBUG_PRINT("[%d] msg is filtered cos not belong to this dev [%d]",ac_head.dev_id_,g_ctx->dev_id_);
        if( cmd == cmd_bpt_rsp_trader_login){
            ret = __trader_login_rsp_handler(gsmeg_hash,ac_head.channel_id_,TRUE);
        }
        if(cmd == cmd_bpt_rsp_monitor_login){
            ret = __user_login_rsp_handler(gsmeg_hash,ac_head.channel_id_,TRUE);
        }
    }
    return ret;
}

static int __filter_nty_msg(long long seq_no, int max_seq_no){
    if(seq_no == max_seq_no+1){
        return FALSE;
    }else{
        return TRUE;
    }
}


static int __nty_gsmeg_msg_handler(z_hash_t *gsmeg_hash ,long long cmd,size_t gsmeg_len,long long nty_seq_no){    
    long long ac_seq_no = flow_seq_manager_get_seq_no(g_ctx->flow_seq_manager_,MARKET_FLOW_TYPE);
    if( FALSE == __filter_nty_msg(nty_seq_no,ac_seq_no)){
        int ret = flow_seq_manager_set_seq_no(g_ctx->flow_seq_manager_,MARKET_FLOW_TYPE,(unsigned long long)nty_seq_no);
        _CHECK_VAL_TRUE_RET( ret!= 0,-1,"set persist seq no failure")

        g_ctx->gtp_pub_->con_len_ = GTP_CONT_LEN;
	    ret =convert_handler_gsmeg2gtp(gsmeg_hash,cmd, gsmeg_len,NULL, g_ctx->gtp_pub_,g_ctx->cvt_handle_,MSG_TYPE_BROADCAST);	
        _CHECK_VAL_TRUE_RET( ret!= 0,-1,"nty msg to channel convert failure")
        PRINT_GTP(g_ctx->gtp_pub_);

        send_gtp_to_all_link(g_ctx->safe_server_link_,g_ctx->link_id_map_,g_ctx->gtp_pub_);
    }else{
        DEBUG_PRINT("nty is filtered: msg_seq_no[%d] vs max_seq_no[%d]",nty_seq_no,ac_seq_no);
    }
    
    return 0;
}        

static int __bct_gsmeg_msg_handler(z_hash_t *gsmeg_hash ,long long cmd,size_t gsmeg_len){    
    g_ctx->gtp_pub_->con_len_ = GTP_CONT_LEN;
	int ret =convert_handler_gsmeg2gtp(gsmeg_hash,cmd, gsmeg_len,NULL, g_ctx->gtp_pub_,g_ctx->cvt_handle_,MSG_TYPE_BROADCAST);	
    _CHECK_VAL_TRUE_RET( ret!= 0,-1,"broadcast msg to channel convert failure")
    PRINT_GTP(g_ctx->gtp_pub_);
    send_gtp_to_all_link(g_ctx->safe_server_link_,g_ctx->link_id_map_,g_ctx->gtp_pub_);
    
    return 0;
}        

static int __guomi_trader_cert_data_rsp_handler(z_hash_t *gsmeg_hash ,long long cmd,size_t gsmeg_len){
    z_array_t *cert_data =(z_array_t *)zH_strfind(gsmeg_hash,"cert_effective_list");
    if(NULL == cert_data){
        Z_LOG_WARNING("cert_effective_list not found");
        return -1;
    }
    z_string_t *trader_id =NULL,*enc_key =NULL,*sign_key =NULL;
    long long enc_key_len =0, sign_key_len =0,validate_flag = 0, system_id = 0;
    
    size_t i = 0;
    z_hash_t *cert_hash = NULL;
    for(;i<cert_data->used_;i++){
    	cert_hash = (z_hash_t *)(cert_data->data_[i]);
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== (trader_id =zH_strfind_string(cert_hash,"trader_id")),"trader_id missed in cert data") 	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== (enc_key =zH_strfind_string(cert_hash,"enc_key")),"enc_key missed in cert data") 	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== (sign_key =zH_strfind_string(cert_hash,"sign_key")),"sign_key missed in cert data") 	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== zH_strfind_ll(cert_hash,"enc_key_len",&enc_key_len),"enc_key_len missed in cert data") 	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== zH_strfind_ll(cert_hash,"sign_key_len",&sign_key_len),"sign_key_len missed in cert data") 	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== zH_strfind_ll(cert_hash,"validate_flag",&validate_flag),"validate_flag missed in cert data") 	    	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== zH_strfind_ll(cert_hash,"system_id",&system_id),"system_id missed in cert data") 	    	
        if(SYSTEMID_BPT == system_id){
            _CHECK_VAL_TRUE_LOG_GOON( 0!= handle_guomi_trader_key_safeinfo(g_ctx->enc_pub_key_manager_,g_ctx->sign_pub_key_manager_,string2str(trader_id),string2str(enc_key),enc_key_len,string2str(sign_key),sign_key_len,(validate_flag)),"handle trader cert for trader[%s] failure ",string2str(trader_id))
        }else{
            ERROR_PRINT("Invalid system_id[%d]",system_id);
        }
    }
    return 0;
}

static int __guomi_trader_mode_data_rsp_handler(z_hash_t *gsmeg_hash ,long long cmd,size_t gsmeg_len){
    z_array_t *enc_mode_data =(z_array_t *)zH_strfind(gsmeg_hash,"encrypt_mode_list");
    if(NULL == enc_mode_data){
        Z_LOG_WARNING("encrypt_mode_list not found");
        return -1;
    }
    z_string_t *trader_id =NULL;
    long long encrypt_mode =0, op_type = 0, system_id = 0;        
    size_t i = 0;
    z_hash_t *end_mode_hash = NULL;
    for(;i<enc_mode_data->used_;i++){
    	end_mode_hash = (z_hash_t *)(enc_mode_data->data_[i]);
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== (trader_id =zH_strfind_string(end_mode_hash,"trader_id")),"trader_id missed in enc_mode data") 	
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== zH_strfind_ll(end_mode_hash,"encrypt_mode",&encrypt_mode),"encrypt_mode missed in enc_mode data") 	
		op_type = (encrypt_mode == ENC_MODE_HARD )? OPTYPE_DEL:OPTYPE_MOD;
    	_CHECK_VAL_TRUE_LOG_GOON(NULL== zH_strfind_ll(end_mode_hash,"system_id",&system_id),"system_id missed in enc_mode data") 	    	
        if(SYSTEMID_BPT == system_id){
            _CHECK_VAL_TRUE_LOG_GOON(0!= handle_guomi_trader_mode_safeinfo(g_ctx->enc_mode_manager_,string2str(trader_id),(encrypt_mode),op_type),"handle trader enc mode[%d] op type[%d] for trader[%s] failure",(encrypt_mode),op_type,string2str(trader_id))
        }else{
            ERROR_PRINT("Invalid system_id[%d]",system_id);
        }
    }
    return 0;
}


static void __cb_on_first_logined(z_hash_t *link_map,long long channel){ 
    //todo --add state check for cert qry rsp
    if(g_ctx->is_first_logined_ == FALSE){
        gsmeg_link_map_push_by_channel(link_map,channel,NULL,0,cmd_bpt_req_qry_certs);
        gsmeg_link_map_push_by_channel(link_map,channel,NULL,0,cmd_bpt_req_qry_encrypt_mode);
        ac_init_net();
        g_ctx->is_first_logined_ = TRUE;
    }    
}

int handle_gsmeg_input(z_gsmeg_t *gsmeg_msg,int channel){
    print_gsmeg_blacklist(g_ctx->gsmeg_print_blacklist_,gsmeg_msg);
    z_hash_t *gsmeg_hash = __get_gsmeghash_from_gsmeg(gsmeg_msg);
    _CHECK_VAL_TRUE_RET(NULL == gsmeg_hash,-1,"get gsmeg hash failure");    
    int ret = 0;
    
    switch(gsmeg_msg->cmd_){
        case cmd_gsmeg_login_rsp:// todo -- dispatch msg according to cmd mask
            //todo  check whether ac_head will be return back for rsp_handler
            ret = gsmeg_login_rsp_handler(g_ctx->gsmeg_link_hashmap_,gsmeg_hash,channel);
            if(ret == 0) __cb_on_first_logined(g_ctx->gsmeg_link_hashmap_,channel);
            break;
        case cmd_gsmeg_repair_rsp:
            ret = gsmeg_repair_rsp_handler(g_ctx->gsmeg_link_hashmap_,gsmeg_hash,channel);
            break;
        default:
            if(TRUE == gsmeg_link_map_is_valid_channel(g_ctx->gsmeg_link_hashmap_,channel)){
                ret = handle_biz_gsmeg(gsmeg_msg,gsmeg_hash);
            }else{
                FATAL_PRINT("channel[%l] status is invalid,msg ignored",channel);
                ret = -1;
            }
    }
    zH_free(gsmeg_hash); 
    return ret;
}

        
int handle_biz_gsmeg(z_gsmeg_t *gsmeg_msg,z_hash_t *gsmeg_hash){        
    int ret =0;
    switch(gsmeg_msg->cmd_){
        case cmd_bpt_rsp_qry_order: 
        case cmd_bpt_rsp_trader_login:
        case cmd_bpt_rsp_submit_ref_price:
        case cmd_bpt_rsp_emerg_pause_review:
        case cmd_bpt_rsp_submit_order:
        case cmd_bpt_rsp_qry_order_amount:
        case cmd_bpt_rsp_qry_match:
        case cmd_bpt_rsp_qry_inst_state:
        case cmd_bpt_rsp_qry_change_inst_state:
        case cmd_bpt_rsp_emerg_delete_ref_price:
        case cmd_bpt_rsp_qry_inst_info:
        case cmd_bpt_rsp_qry_online_traders:
        case cmd_bpt_rsp_qry_session_info:
        case cmd_bpt_rsp_modify_init_price:
        case cmd_bpt_rsp_qry_bm_price:
        case cmd_bpt_rsp_kick_trader:
        case cmd_bpt_rsp_qry_matching_market_quotation_2:
        case cmd_bpt_rsp_emerg_limit_new_order:
        case cmd_bpt_rsp_emerg_submit_ref_price:
        case cmd_bpt_rsp_modify_round_price:
        case cmd_bpt_rsp_emerg_pause_restore:
        case cmd_bpt_rsp_qry_sys_time:
        case cmd_bpt_rsp_qry_capital:
        case cmd_bpt_rsp_qry_init_price:
        case cmd_bpt_rsp_monitor_login:
        case cmd_bpt_rsp_qry_round_quotation:
        case cmd_bpt_rsp_submit_bm_price:
        case cmd_bpt_rsp_qry_matching_market_quotation:
        case cmd_bpt_rsp_qry_ref_price:
        case cmd_bpt_rsp_emerg_finish:
        case cmd_bpt_rsp_qry_market_info:
        case cmd_bpt_rsp_emerg_pause:
        case cmd_bpt_rsp_qry_match_2:
        case cmd_bpt_rsp_qry_seat_info:
        case cmd_bpt_rsp_qry_client_info:
        case cmd_bpt_rsp_qry_keep_order:
        case cmd_bpt_rsp_qry_pause_records:
        case cmd_bpt_rsp_qry_init_price_modify_records:
        case cmd_bpt_rsp_qry_finish_records:
        case cmd_bpt_rsp_qry_order_2:
        case cmd_bpt_rsp_qry_order_amount_2:
        case cmd_bpt_rsp_qry_ref_price_2:
        case cmd_bpt_rsp_modify_bm_price:
        case cmd_bpt_rsp_publish_bm_price:
        case cmd_bpt_rsp_qry_modify_price_records:
        case cmd_bpt_rsp_qry_continue_order:
            ret = __rsp_gsmeg_msg_handler(gsmeg_hash,(long long)(gsmeg_msg->cmd_),gsmeg_msg->size_);
        	break;
        case cmd_bpt_brc_inst_state:
        case cmd_bpt_brc_sys_cancel_order:
        case cmd_bpt_brc_st_dir:
        case cmd_bpt_brc_init_price:
        case cmd_bpt_brc_bpt_price:
            ret = __nty_gsmeg_msg_handler(gsmeg_hash,(long long)(gsmeg_msg->cmd_),gsmeg_msg->size_,gsmeg_msg->seq_);
        	break;
        case cmd_bpt_brc_round_quotation:
        case cmd_bpt_brc_matching_market_quotation:
        case cmd_bpt_brc_sys_time:
            ret = __bct_gsmeg_msg_handler(gsmeg_hash,(long long)(gsmeg_msg->cmd_),gsmeg_msg->size_);
        	break;
        case cmd_bpt_brc_kick_trader:
        	ret = __trader_force_logout(gsmeg_hash);
        	break;	
        case cmd_bpt_rsp_qry_certs:
        case cmd_bpt_brc_update_cert:
            ret = __guomi_trader_cert_data_rsp_handler(gsmeg_hash,(long long)(gsmeg_msg->cmd_),gsmeg_msg->size_);;
        	break;
        case cmd_bpt_rsp_qry_encrypt_mode:
        case cmd_bpt_brc_update_encrypt_mode:
            ret =  __guomi_trader_mode_data_rsp_handler(gsmeg_hash,(long long)(gsmeg_msg->cmd_),gsmeg_msg->size_);;
        	break;
        case cmd_bpt_rsp_monitor_logout:
        case cmd_bpt_rsp_trader_logout:
            ret =0;
            break;
        default:
            ERROR_PRINT("cmd[%d] is unsupported now",gsmeg_msg->cmd_);
            ret = -1;
    }
    
	return ret;
}

